package com.wasu.sdk_ott.receiver

import android.content.Context
import android.text.TextUtils
import android.util.Log
import com.alibaba.fastjson.JSON
import com.alibaba.fastjson.JSONArray
import com.alibaba.fastjson.JSONObject
import com.wasu.UILApplication
import com.wasu.constant.Config
import com.wasu.constant.SYSTEM_CATEGORY_4K_IPDVB_HUIFANG
import com.wasu.constant.TAG
import com.wasu.database.keyvalue.KeyValueData
import com.wasu.rxcache.RxCache
import com.wasu.sdk_ott.http.live.IPLIVE_CACHE_AUTH_KYE
import com.wasu.sdk_ott.http.live.IPLIVE_CACHE_CHANNEL_KYE
import com.wasu.sdk_ott.http.live.IPLIVE_CACHE_PROGRAM_ALLDAY_KYE
import com.wasu.sdk_ott.http.live.IPLIVE_CACHE_PROGRAM_KYE
import com.wasu.sdk_ott.http.live.IpLiveLoader
import com.wasu.sdk_ott.http.live.UnifiedAuthLoader
import com.wasu.sdk_ott.service.LiveVersionHelper
import com.wasu.sdk_ott.utils.AppInitHelper
import com.wasu.sdk_ott.utils.WasuTvModelUtil

/**
 * <p>------------------------------------------------------
 * <p>Copyright (C) 2020 wasu company, All rights reserved.
 * <p>------------------------------------------------------
 * <p> 开机分组频道类缓存，DVB模式频道授权列表保存和查询
 * <p>
 *
 * @author Created by zhangmz
 * @date on 2023/10/9
 */
object LiveChannelAuthHelper {

    /**
     * AAA和流量网关接口请求成功后，开始请求IP直播管理系统数据并缓存
     */
    @JvmStatic
    fun updateChannel(context: Context? = UILApplication.getInstance().application.applicationContext){
        // 优先初始化，再取到aaa结果后拿到region，修改缓存文件夹路径
        RxCache.Builder().diskDir(AppInitHelper.getRxCachePath(context)).build()

        // 首次缓存IP直播管理系统相关接口
        val ipLiveLoader = IpLiveLoader()
        Log.e(TAG, "----->> IP start query channel group")
        // 异步请求分组频道并缓存
        ipLiveLoader.queryChannelGroupAsync(
            strategy = "1",
            defaultKey = IPLIVE_CACHE_CHANNEL_KYE,
            success = {
                Log.e(TAG, "<<----- IP end query channel group success")
            },
            failure = {
                Log.e(TAG, "<<----- IP end query channel group failure, error:$it")
            }
        )
        Log.e(TAG, "----->> IP start query program all today")
        // 异步请求所有频道当天节目单并缓存
        ipLiveLoader.queryProgramListAsync(
            type = "1",
            strategy = "1",
            defaultKey = IPLIVE_CACHE_PROGRAM_ALLDAY_KYE,
            success = {
                Log.e(TAG, "<<----- IP end query program all today success")
            },
            failure = {
                Log.e(TAG, "<<----- IP end query program all today failure, error:$it")
            }
        )
        // DVB模式下，异步请求频道授权列表并缓存
        if (!WasuTvModelUtil.isbIpMode()){
            Log.e(TAG, "----->> IP start query channel auth list")
            ipLiveLoader.queryChannelAuthAsync(
                strategy = "1",
                defaultKey = IPLIVE_CACHE_AUTH_KYE,
                success = {
                    Log.e(TAG, "<<----- IP end query channel auth list success")
                },
                failure = {
                    Log.e(TAG, "<<----- IP end query channel auth list failure, error:$it")
                }
            )
        }
        // 异步请求版本号接口，保存在数据库中，并且以eVersion数组为前提，对比版本号，将所有频道所有天数节目单分文件缓存
        Log.e(TAG, "----->> IP start query channel program version")
        ipLiveLoader.queryChProVersionAsync(
            success = {
                Log.e(TAG, "<<----- IP end query channel program version success")
                LiveVersionHelper.analysisLiveVersion(context, it)
            },
            failure = {
                Log.e(TAG, "<<----- IP end query channel program version failure, error:$it")
            }
        )
    }

    /**
     * 判断某个频道是否授权
     */
    fun loadAuthChannel(channelId: String?, capIdStr: String?, type: String?): String {
        Log.v(TAG, "loadAuthChannel, channelId:$channelId; capIdStr:$capIdStr; type:$type")
        var auth = "false"
        if (channelId.isNullOrEmpty()){
            return auth
        }
        if (capIdStr?.isNotEmpty() == true){
            val region = Config.getRegion()
            val key = if (region.isNullOrEmpty()) IPLIVE_CACHE_AUTH_KYE else "${region}_$IPLIVE_CACHE_AUTH_KYE"
            auth = RxCache.getDefault().loadSync<String>(
                key,
                String::class.java
            )?.data?.let { data ->
                Log.v(TAG, "load cache channel auth success1, result:$data")
                verifyChannelAuthForCapId(capIdStr, data)
            }?: "false"
            return auth
        }
        val category = if ("huifang" == type) SYSTEM_CATEGORY_4K_IPDVB_HUIFANG else ""
        IpLiveLoader(category = category).queryChannelSync(
            channelId,
            category = category,
            success = {channel ->
                Log.e(TAG, "loadAuthChannel, channel:$channel")
                if (WasuTvModelUtil.isbIpMode() || "huifang" == type){
                    val channelJsonList = JSON.parseObject(channel)
                    val channelJsonArray = channelJsonList.getJSONArray("chList")
                    if (channelJsonArray != null && channelJsonArray.size > 0){
                        val channelJson = channelJsonArray.getJSONObject(0)
                        auth = if (channelJson.containsKey("ipLive")){
                            var hasUrl = "false"
                            val channelIpLive = channelJson.getJSONObject("ipLive")
                            if (channelIpLive != null){
                                val backUrlsArray = channelIpLive.getJSONArray("tsPlaybackUrls")
                                if (backUrlsArray.isNotEmpty()){
                                    for (i in backUrlsArray.indices){
                                        val backUrlObject = backUrlsArray.getJSONObject(i)
                                        if (backUrlObject.containsKey("playUrl") && backUrlObject.getString("playUrl").isNotEmpty()){
                                            hasUrl = "true"
                                            break
                                        }
                                    }
                                }
                            }
                            // 业务数据管理系统配置免鉴权开关，由body联网广播请求保存，0：开启；1：不开启，默认0
                            val openAuth = KeyValueData.instance().query("openAuth")?.value?: "1"
                            Log.e(TAG, "loadAuthChannel, hasUrl:$hasUrl; openAuth:$openAuth")
                            if ("true" == hasUrl){
                                var ppvId = if (channelIpLive.containsKey("hfPpvId")) channelIpLive.getString("hfPpvId") else ""
                                if (TextUtils.isEmpty(ppvId)){
                                    ppvId = if (channelIpLive.containsKey("ppvid")) channelIpLive.getString("ppvid") else ""
                                }
                                if (TextUtils.isEmpty(ppvId)){
                                    "false"
                                }else {
                                    runCatching {
                                        val authResult = UnifiedAuthLoader().queryLiveUnifiedAuth(ppvId, channelId)
                                        Log.v(TAG, "loadAuthChannel------>> ppvId:$ppvId; channelId:$channelId; authResult:$authResult")
                                        val authJson = JSON.parseObject(authResult)
                                        if (authJson.containsKey("retCode") && "0" == authJson.getString("retCode")){
                                            val authArray = authJson.getJSONArray("contents")
                                            if (authArray.isNullOrEmpty()){
                                                if ("0" == openAuth) "true" else "false"
                                            }else {
                                                val channelAuthJson = authArray.getJSONObject(0)
                                                ("0" == channelAuthJson.getString("ordState")).toString()
                                            }
                                        }else {
                                            if ("0" == openAuth) "true" else "false"
                                        }
                                    }.getOrDefault(if ("0" == openAuth) "true" else "false")
                                }
                            }else {
                                hasUrl
                            }
                        }else {
                            Log.e(TAG, "loadAuthChannel, channelJson: err")
                            "false"
                        }
                    }
                }else {
                    val region = Config.getRegion()
                    val key = if (region.isNullOrEmpty()) IPLIVE_CACHE_AUTH_KYE else "${region}_$IPLIVE_CACHE_AUTH_KYE"
                    auth = RxCache.getDefault().loadSync<String>(
                        key,
                        String::class.java
                    )?.data?.let { d ->
                        Log.v(TAG, "load cache channel auth success2, result:$d")
                        verifyChannelAuth(channel, d)
                    }?: "false"
                }
            }
        )
        return auth
    }

    /**
     * 验证单个频道是否授权
     */
    private fun verifyChannelAuth(channelListJson: String, authResult: String): String{
        return runCatching {
            Log.v(TAG, "verifyChannelAuth, channelListJson:$channelListJson")
            val channelListObject = JSONObject.parseObject(channelListJson)
            var isPurchased = "false"
            if (!channelListObject.containsKey("chList") || channelListObject.getString("chList").isNullOrEmpty()){
                return isPurchased
            }
            val channelArray = channelListObject.getJSONArray("chList")
            if (channelArray.isEmpty()){
                return isPurchased
            }
            val channelObject = channelArray.getJSONObject(0)
            if (!channelObject.containsKey("dvbLive") || channelObject.getString("dvbLive").isNullOrEmpty()){
                return isPurchased
            }
            val dvbObject = channelObject.getJSONObject("dvbLive")
            if (!dvbObject.containsKey("capId") || dvbObject.getString("capId").isNullOrEmpty()){
                return isPurchased
            }
            val authObject = JSONObject.parseObject(authResult)
            if (!authObject.containsKey("capIds") || authObject.getString("capIds").isNullOrEmpty()){
                return isPurchased
            }
            val auth = authObject.getString("capIds")
            val capIds = dvbObject.getString("capId").split(",")
            Log.v(TAG, "verifyChannelAuth, capIds:$capIds; auth:$auth")
            for (m in capIds.indices){
                val temp = capIds[m]
                if (!temp.contains(":")){
                    isPurchased = if (auth.contains(temp)) "true" else "false"
                    break
                }else {
                    val temps = temp.split(":")
                    for (n in temps.indices){
                        if (auth.contains(temps[n])){
                            isPurchased = "true"
                            break
                        }
                    }
                }
            }
            isPurchased
        }.getOrDefault("false")
    }

    /**
     * capId为条件获得授权结果
     */
    private fun verifyChannelAuthForCapId(capIdStr: String, authResult: String): String{
        return runCatching {
            var isPurchased = "false"
            val authObject = JSONObject.parseObject(authResult)
            if (!authObject.containsKey("capId") || authObject.getString("capId").isNullOrEmpty()){
                return isPurchased
            }
            val auth = authObject.getString("capId")
            val capIds = capIdStr.split(",")
            for (m in capIds.indices){
                val temp = capIds[m]
                if (!temp.contains(":")){
                    isPurchased = if (auth.contains(temp)) "true" else "false"
                    break
                }else {
                    val temps = temp.split(":")
                    for (n in temps.indices){
                        if (auth.contains(temps[n])){
                            isPurchased = "true"
                            break
                        }
                    }
                }
            }
            isPurchased
        }.getOrDefault("false")
    }

    /**
     * 判断所有频道是否授权
     */
    fun loadAuthChannelGroup(
        channelGroup: String? = null,
        execute: (authResult: String?) -> Unit
    ) {
        runCatching {
            verifyChannelGroup(channelGroup){
                it?.let { bouArray ->
                    val region = Config.getRegion()
                    val key = if (region.isNullOrEmpty()) IPLIVE_CACHE_AUTH_KYE else "${region}_$IPLIVE_CACHE_AUTH_KYE"
                    Log.v(TAG, "loadAuthChannelGroup, key:$key")
                    RxCache.getDefault().loadSync<String>(
                        key,
                        String::class.java
                    )?.data?.let { auth ->
                        Log.v(TAG, "load cache channel auth success, result:$auth")
                        for (i in bouArray.indices){
                            val bouObject = bouArray.getJSONObject(i)
                            if (!bouObject.containsKey("chList") || bouObject.getString("chList").isNullOrEmpty()){
                                continue
                            }
                            val channelArray = bouObject.getJSONArray("chList")
                            if (channelArray.isEmpty()){
                                continue
                            }
                            for (j in channelArray.indices){
                                val channelObject = channelArray.getJSONObject(j)
                                if (!channelObject.containsKey("dvbLive") || channelObject.getString("dvbLive").isNullOrEmpty()){
                                    channelObject["isPurchased"] = "0"
                                    continue
                                }
                                val dvbObject = channelObject.getJSONObject("dvbLive")
                                if (!dvbObject.containsKey("capId") || dvbObject.getString("capId").isNullOrEmpty()){
                                    channelObject["isPurchased"] = "0"
                                    continue
                                }
                                val capIds = channelObject.getString("capId").split(",")
                                for (m in capIds.indices){
                                    val temp = capIds[m]
                                    if (!temp.contains(":")){
                                        channelObject["isPurchased"] = if (auth.contains(temp)) "1" else "0"
                                    }else {
                                        val temps = temp.split(":")
                                        channelObject["isPurchased"] = "0"
                                        for (n in temps.indices){
                                            if (auth.contains(temps[n])){
                                                channelObject["isPurchased"] = "1"
                                                break
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        execute(channelGroup)
                    }?: execute(channelGroup)
                }?: execute(channelGroup)
            }
        }.onFailure {
            it.printStackTrace()
            execute(channelGroup)
        }
    }

    /**
     * 解析分组频道，更新节目单缓存
     * TODO LIVE 循环缓存每个频道所有天数节目单，目前未调用，可以先看下直播查询节目单的效果怎么样再确认是否添加
     * TODO LIVE 如果这里需要添加请求，需要同现网一样，做个是否有缓存的判断，意思没缓存再请求，正常情况下升级后只请求一次
     */
    private fun analysisChannelUpdateProgram(
        channelGroup: String? = null
    ){
        runCatching {
            verifyChannelGroup(channelGroup){
                Log.v("aaaaa", "------------>> 解析完成分组列表")
                it?.let { bouArray ->
                    val ipLiveLoader = IpLiveLoader()
                    for (i in bouArray.indices){
                        val bouObject = bouArray.getJSONObject(i)
                        if (!bouObject.containsKey("chList") || bouObject.getString("chList").isNullOrEmpty()){
                            continue
                        }
                        val channelArray = bouObject.getJSONArray("chList")
                        if (channelArray.isEmpty()){
                            continue
                        }
                        Log.v("aaaaa", "------------>> 解析完成频道列表")
                        for (j in channelArray.indices){
                            val channelObject = channelArray.getJSONObject(j)
                            if (!channelObject.containsKey("chId") || channelObject.getString("chId").isNullOrEmpty()){
                                continue
                            }
                            val channelId = channelObject.getString("chId")
                            Log.v("aaaaa", "------------>> 解析完成频道id，channelId:$channelId")
                            val programCacheKey = "${IPLIVE_CACHE_PROGRAM_KYE}_$channelId"
                            ipLiveLoader.queryProgramListAsync(type = "2", channelId = channelId, defaultKey = programCacheKey)
                        }
                    }
                }
            }
        }.onFailure { it.printStackTrace() }
    }

    /**
     * 验证分组频道数据是否正常
     */
    private fun verifyChannelGroup(
        channelGroup: String? = null,
        execute: (channelArray: JSONArray?) -> Unit
    ){
        if (channelGroup.isNullOrEmpty()){
            execute(null)
            return
        }
        val jsonObject = JSONObject.parseObject(channelGroup)
        if (!jsonObject.containsKey("bList") || jsonObject.getString("bList").isNullOrEmpty()){
            Log.v(TAG, "loadAuthGroup, channel bList isNullOrEmpty")
            execute(null)
            return
        }
        val jsonArray = jsonObject.getJSONArray("bList")
        if (jsonArray.isEmpty()){
            Log.v(TAG, "loadAuthGroup, channel jsonArray isEmpty")
            execute(null)
            return
        }
        execute(jsonArray)
    }

}